﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace iTeachSoft.CoreObjects.win32
{
    using System;
    using System.Runtime.InteropServices;

    namespace MsdnMag
    {
        public class HookEventArgs : EventArgs
        {
            public int HookCode;    // Hook code
            public IntPtr wParam;   // WPARAM argument
            public IntPtr lParam;   // LPARAM argument
        }

        // Hook Types  
        public enum HookType : int
        {
            WH_JOURNALRECORD = 0,
            WH_JOURNALPLAYBACK = 1,
            WH_KEYBOARD = 2,
            WH_GETMESSAGE = 3,
            WH_CALLWNDPROC = 4,
            WH_CBT = 5,
            WH_SYSMSGFILTER = 6,
            WH_MOUSE = 7,
            WH_HARDWARE = 8,
            WH_DEBUG = 9,
            WH_SHELL = 10,
            WH_FOREGROUNDIDLE = 11,
            WH_CALLWNDPROCRET = 12,
            WH_KEYBOARD_LL = 13,
            WH_MOUSE_LL = 14
        }

        [StructLayout(LayoutKind.Sequential)]
        public class KBDLLHOOKSTRUCT
        {
            public UInt32 vkCode;
            public UInt32 scanCode;
            public KBDLLHOOKSTRUCTFlags flags;
            public UInt32 time;
            public IntPtr dwExtraInfo;
        }

        [Flags()]
        public enum KBDLLHOOKSTRUCTFlags : int
        {
            LLKHF_EXTENDED = 0x01,
            LLKHF_INJECTED = 0x10,
            LLKHF_ALTDOWN = 0x20,
            LLKHF_UP = 0x80,
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public int mouseData;
            public int flags;
            public int time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator System.Drawing.Point(POINT p)
            {
                return new System.Drawing.Point(p.X, p.Y);
            }

            public static implicit operator POINT(System.Drawing.Point p)
            {
                return new POINT(p.X, p.Y);
            }
        }

        public class WindowsHooks
        {
            public const int WM_KEYUP = 0x0101;
            public const int WM_SYSKEYUP = 0x0105;
            public const int WM_LBUTTONDOWN = 0x0201;

            // Filter function delegate
            public delegate int HookProc(int code, IntPtr wParam,
               IntPtr lParam);

            // Internal properties
            protected IntPtr m_hhook = IntPtr.Zero;
            protected HookProc m_filterFunc = null;
            protected HookType m_hookType;

            // Event delegate
            public delegate void HookEventHandler(object sender,
               HookEventArgs e);

            // Event: HookInvoked 
            public event HookEventHandler HookInvoked;
            protected void OnHookInvoked(HookEventArgs e)
            {
                if (HookInvoked != null)
                    HookInvoked(this, e);
            }

            // Class constructor(s)
            public WindowsHooks(HookType hook)
            {
                m_hookType = hook;
                m_filterFunc = new HookProc(this.CoreHookProc);
            }
            public WindowsHooks(HookType hook, HookProc func)
            {
                m_hookType = hook;
                m_filterFunc = func;
            }

            // Default filter function
            public int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
            {
                if (code < 0)
                    return CallNextHookEx(m_hhook, code, wParam, lParam);

                // Let clients determine what to do
                HookEventArgs e = new HookEventArgs();
                e.HookCode = code;
                e.wParam = wParam;
                e.lParam = lParam;
                OnHookInvoked(e);

                // Yield to the next hook in the chain
                return CallNextHookEx(m_hhook, code, wParam, lParam);
            }

            // Install the hook
            public void Install()
            {
                m_hhook = SetWindowsHookEx(
                    m_hookType,
                    m_filterFunc,
                    IntPtr.Zero,
                    0);

                if (m_hhook == IntPtr.Zero)
                    Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
            }

            // Uninstall the hook
            public void Uninstall()
            {
                UnhookWindowsHookEx(m_hhook);
            }

            #region Win32 Imports

            // Win32: SetWindowsHookEx()
            [DllImport("user32.dll")]
            protected static extern IntPtr SetWindowsHookEx(HookType code,
                HookProc func,
                IntPtr hInstance,
                int threadID);


            // Win32: UnhookWindowsHookEx()
            [DllImport("user32.dll")]
            protected static extern int UnhookWindowsHookEx(IntPtr hhook);

            // Win32: CallNextHookEx()
            [DllImport("user32.dll")]
            protected static extern int CallNextHookEx(IntPtr hhook,
                int code, IntPtr wParam, IntPtr lParam);

            #endregion
        }
    }
}
